package com.zp.thread;
/**
 * 改程序模拟了线程的同步问题：
 * a)结果不确定，如下：
 *   第一次执行结果：
 *   	存款余额：200
 *	 	取出现金：800
 *	 	存款余额：200
 *	 	取出现金：800
 *	 第二次执行结果：
 *	 	存款余额：200
 *	 	取出现金：800
 *	 	存款余额：-600
 *	 	取出现金：800
 * b)结果分析：
 *   由于两个线程哪个先进入CPU中执行不确定，假如两个线程同时进入，
 *   在同一时刻执行了getMoney()方法中的money -= num;就会得到
 *   第一个结果；若是其中一个线程比另一个执行快，则会得到结果二；
 * c)解决线程同步方案：
 * 	 使用synchronized关键字修饰所要执行的方法：
 * 	 如程序中在getMoney()方法中加上synchronized关键字：
 * 	 public synchronized int getMoney(int num){}
 * 	 结果：存款余额：200
 *	      取出现金：800
 *		  取出现金：-3
 */
public class SynchronizedTest {
	public static void main(String[] args) {
		//一个对象：就是一个银行账户；
		Bank bank = new Bank();
		//一个线程：就是这个账户的一个线程(比如柜台取款)
		Thread t1 = new MoneyThread(bank);
		//另一个线程：就是这个账户的另一个线程(比如取款机取款)
		Thread t2 = new MoneyThread(bank);
		
		t1.start();
		t2.start();
	}
	
}

class Bank{
	//存入银行的的现金为1000；
	private int money = 1000;
	//从银行取钱的方法
	public synchronized int getMoney(int num){
		if(money < 0){
			return -1;
		}
		else if(num < 0){
			return -2;
		}
		else if(num > money){
			return -3;
		}
		else {
			try {
				//模拟取款时的处理时间：1秒；
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			money -= num;
			System.out.println("存款余额："+money);
			return num;
		}
	}
}

class MoneyThread extends Thread{
	//该线程对账户的引用：这样该线程就可以操作该账户了；
	private Bank bank;
	
	public MoneyThread(Bank bank){
		this.bank = bank;
	}
	
	@Override
	public void run() {
		System.out.println("取出现金："+bank.getMoney(800));
	}
}
